home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 11
/
Cream of the Crop 11-2.iso
/
os2
/
gnucal.zip
/
gcal_rc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-18
|
56KB
|
1,876 lines
/*
* gcal_rc.c: Pool of special functions necessary for managing the fixed dates
*
*
* Copyright (C) 1994, 1995 Thomas Esken
*
* This software doesn't claim completeness, correctness or usability.
* On principle I will not be liable for any damages or losses (implicit
* or explicit), which result from using or handling my software.
* If you use this software, you agree without any exception to this
* agreement, which binds you LEGALLY !!
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the `GNU General Public License' as published by
* the `Free Software Foundation'; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the `GNU General Public License'
* along with this program; if not, write to the:
* Free Software Foundation
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*/
/*
* Include definition header file to see whether USE_RC is defined there.
* compile this module only if USE_RC is defined, otherwise skip it.
*/
#include "gcal_tai.h"
#if USE_RC
# ifdef RCSID
static char rcsid[]="$Id: gcal_rc.c 0.39 1995/12/18 00:03:09 tom Exp $";
# endif
/*
* Include header files
*/
# if HAVE_CTYPE_H
# include <ctype.h>
# endif
# include "gcal.h"
/*
* Function prototypes
*/
# if __cplusplus
extern "C"
{
# endif
/*
************************************************** Defined in `gcal_hdy.c'
*/
IMPORT int
eval_holiday __P_(( int day,
const int month,
const int year,
const int wd,
const Bool forwards));
/*
************************************************** Defined in `gcal_tty.c'
*/
IMPORT void
print_text __P_(( FILE *fp,
char *txt_line,
const Dmode_enum mode));
/*
************************************************** Defined in `gcal_utl.c'
*/
IMPORT void
my_error __P_((const int exit_status,
const char *module_name,
const int module_line,
const char *var_name,
const int var_contents));
IMPORT int
my_atoi __P_((const char *s));
IMPORT int
compare_d_m_name __P_((const char *s,
const Cmode_enum mode));
IMPORT Ulint
date2num __P_((const int day,
const int month,
const int year));
IMPORT Bool
jdate2sdate __P_(( int jdate,
const int is_leap_year,
int *day,
int *month));
IMPORT int
weekday_of_date __P_((const int day,
const int month,
const int year));
IMPORT int
day_of_year __P_((const int day,
const int month,
const int year));
IMPORT int
days_of_february __P_((const int year));
IMPORT Bool
valid_date __P_((const int day,
const int month,
const int year));
IMPORT int
weekno2jday __P_(( int week,
const int year));
IMPORT int
knuth_easter_formula __P_((const int year));
/*
************************************************** Defined in `gcal_rc.c'
*/
EXPORT void
rc_clean_flags __P_((void));
EXPORT char *
rc_get_date __P_(( char *ptr_char,
Bool *is_weekday_mode,
int *d,
int *m,
int *y,
int *n,
int *len,
char *hc,
int *hn,
int *hwd,
const char *filename,
const int line,
const char *line_buffer,
const Bool on_error_exit));
EXPORT Bool
precomp_nth_wd __P_(( int diff,
const int wd,
int *n,
int *day,
int *month,
int *year,
const Cmode_enum mode));
EXPORT Bool
precomp_date __P_(( int diff,
const int wd,
int *day,
int *month,
const int year,
const Cmode_enum mode));
EXPORT Bool
set_dvar __P_((const char *line_buffer,
const char *filename,
const int line,
const Dvar_enum mode));
EXPORT void
nth_weekday_of_month __P_(( int *d,
int *m,
int *y,
const int *n,
Bool *is_weekday_mode));
EXPORT void
prev_date __P_((int *day,
int *month,
int *year));
EXPORT void
next_date __P_((int *day,
int *month,
int *year));
EXPORT void
num2date __P_((Ulint julian_days,
int *day,
int *month,
int *year));
EXPORT Slint
d_between __P_((const int d1,
const int m1,
const int y1,
const int d2,
const int m2,
const int y2));
EXPORT Slint
w_between __P_((const int d1,
const int m1,
const int y1,
const int d2,
const int m2,
const int y2));
EXPORT Slint
m_between __P_((const int m1,
const int y1,
const int m2,
const int y2));
LOCAL void
dvar_warning __P_((const int exit_status,
const char dvar,
const char *filename,
const int line,
const char *text));
# if __cplusplus
}
# endif
/*
* Declare public(extern) variables
*/
IMPORT const int dvec[MONTH_MAX]; /* Amount of days in months' */
IMPORT const int mvec[MONTH_MAX]; /* Number of past days of month */
IMPORT Dvar_struct rc_dvar[RC_DVAR_MAX]; /* Date variables a[=`mmdd']...z[] (`yyyy'@{a|b|...|z}[[-]<n>]) */
IMPORT int len_year_max; /* String length of the maximum year able to compute */
IMPORT int warning_level; /* --debug[=0...WARN_LVL_MAX] */
IMPORT int start_day; /* -s<0,1...7|day name> */
IMPORT int day; /* Current day */
IMPORT int month; /* Current month */
IMPORT int year; /* Current year */
IMPORT int fiscal_month; /* Starting month of a fiscal year */
IMPORT int is_leap_year; /* Is current year a leap year? */
IMPORT Bool rc_period_flag; /* [-c]<<<<n>>[<d|w|+|-]>|`mmdd'|`mmww[w]'<n>> */
IMPORT Bool rc_period_list; /* [-c]l */
IMPORT Bool rc_tomorrow_flag; /* [-c]t */
IMPORT Bool rc_week_flag; /* [-c]w */
IMPORT Bool rc_month_flag; /* [-c]m */
IMPORT Bool rc_year_flag; /* [-c]y */
IMPORT Bool rc_week_year_flag; /* [-c<<n>>]w */
IMPORT Bool rc_forwards_flag; /* [-c<<n>|w|m|y>]+ */
IMPORT Bool rc_backwards_flag; /* [-c<<n>|w|m|y>]- */
IMPORT Bool is_3month_mode; /* Argument is `.' or `.+' or `.-' */
IMPORT Bool is_3month_mode2; /* Argument is `..' -> current quarter of actual year */
IMPORT Bool adate_set; /* [-c]<n>w and actual date modified */
/*
Define local(static) variables
*/
LOCAL char str[MAXLEN+1]; /* General purpose text buffer */
# ifdef ANSI_PROTO
PUBLIC void
rc_clean_flags (void)
# else /* !ANSI_PROTO */
PUBLIC void
rc_clean_flags ()
# endif /* !ANSI_PROTO */
/*
Clean all global flags (except `rc_period_list'),
which are related to the fixed date warning period
*/
{
rc_tomorrow_flag=rc_week_flag=rc_month_flag=rc_year_flag
=rc_week_year_flag=rc_forwards_flag=rc_backwards_flag=rc_period_flag = FALSE;
}
# ifdef ANSI_PROTO
PUBLIC char *
rc_get_date ( char *ptr_char,
Bool *is_weekday_mode,
int *d,
int *m,
int *y,
int *n,
int *len,
char *hc,
int *hn,
int *hwd,
const char *filename,
const int line,
const char *line_buffer,
const Bool on_error_exit)
# else /* !ANSI_PROTO */
PUBLIC char *
rc_get_date (ptr_char, is_weekday_mode, d, m, y, n, len, hc, hn, hwd,
filename, line, line_buffer, on_error_exit)
char *ptr_char;
Bool *is_weekday_mode;
int *d;
int *m;
int *y;
int *n;
int *len;
char *hc;
int *hn;
int *hwd;
const char *filename;
const int line;
const char *line_buffer;
const Bool on_error_exit;
# endif /* !ANSI_PROTO */
/*
Converts the textual/string `date' of a RC-file line to a numerical date
and returns a pointer to `text'-part of RC-file line(warning message)
or if a @... or *... day is encoded in date part and year is set to 0000
in line, then function returns holiday_mode_char(date variable) or
upper case characters 'D' or 'W' in &hc, day displacement in &hn and a
possible weekday name(mo...su) converted to a number (1...7) in &hwd for
further managing of such a line. if any invalid date is given in line,
then function either returns -1 in &y or leaves program with error_message
(depending on mode of operation resp., contents of `on_error_exit' variable).
*/
{
register int i;
auto char str8[8]; /* For date parts, lenght of 7 chars+'\0' maximum! */
auto Bool is_hdy_mode=FALSE;
*hc = '\0';
(*len)=(*hn)=(*hwd)=(*n)=i = 0;
/*
Get year
*/
while ( *ptr_char
&& !MY_ISSPACE(*ptr_char)
&& isdigit(*ptr_char)
&& (i < len_year_max))
str8[i++] = *ptr_char++;
str8[i] = '\0';
*y = my_atoi (str8);
*len = i;
/*
Get month
*/
i = 0;
while ( *ptr_char
&& !MY_ISSPACE(*ptr_char)
&& (i < 2))
str8[i++] = *ptr_char++;
if (i)
if ( ( isupper(str8[i-1])
|| islower(str8[i-1]))
&& ( isupper(*ptr_char)
|| islower(*ptr_char)))
str8[i++] = *ptr_char++;
str8[i] = '\0';
*m = my_atoi (str8);
if (!*m)
/*
Check for short (2...3 character) textual month name.
does not work for month July in case a textual two character lenght
month name is given, because `ju' is always set to month June.
*/
*m = compare_d_m_name (str8, MOnth);
else
/*
Error, invalid month field
*/
if ( i == 3
|| ( (i == 2)
&& (!isdigit(str8[1]))))
{
if (on_error_exit)
my_error (122, filename, line, line_buffer, *m);
*y = -1;
}
/*
Check if @... date variable statement or *... statement is given
*/
if (i)
{
*len += i;
if (*str8 == RC_HDY_CHAR)
{
is_hdy_mode = TRUE;
if (i == 2)
*hc = (char)tolower(str8[1]);
}
else
if (*str8 == RC_NWD_CHAR)
{
is_hdy_mode = TRUE;
if ( (i == 2)
&& ( toupper(str8[1]) == 'D'
|| toupper(str8[1]) == 'W'))
*hc = (char)toupper(str8[1]);
else
{
if (i == 2)
/*
Error, invalid mode specifying character given
*/
*hc = (char)toupper(str8[1]);
else
/*
Error, no mode specifying character given
*/
*hc = *str8;
}
}
}
/*
If special value 99 for month `m' is given,
set month to 12 (december)
*/
if (*m == 99)
*m = MONTH_MAX;
/*
Error, invalid month field
*/
if ( !is_hdy_mode
&& ( *m > MONTH_MAX
|| ( !*m
&& ( ( (i == 1)
&& !isdigit(*str8))
|| ( (i == 2)
&& ( !isdigit(*str8)
|| !isdigit(str8[1])))
|| ( (i == 3)
&& ( !isdigit(*str8)
|| !isdigit(str8[1])
|| !isdigit(str8[2])))))))
{
if (on_error_exit)
my_error (122, filename, line, line_buffer, *m);
*y = -1;
}
/*
Get day (maximum 3 characters in this case, template is either `dd', `ww' or `www')
resp., @... date variable or *... statement (maximum 7 characters in this case,
template is: -nnn`www')
*/
i = 0;
while ( *ptr_char
&& !MY_ISSPACE(*ptr_char)
&& (i < ((is_hdy_mode) ? 7 : 3)))
str8[i++] = *ptr_char++;
str8[i] = '\0';
*d = atoi (str8);
if (i)
*len += i;
*is_weekday_mode = FALSE;
ptr_char--;
if ( isupper(*ptr_char)
|| islower(*ptr_char)
|| ( (i < 3)
&& !is_hdy_mode))
ptr_char++;
if (!is_hdy_mode)
{
/*
Check for textual day name (either two or three characters),
template `ww' or `www'
*/
if (!*d)
{
*d = compare_d_m_name (str8, DAy);
if (*d)
{
*is_weekday_mode = TRUE;
if (isdigit(str8[i-1]))
(*len)--;
}
if (!*d)
{
i = 0;
while (isdigit(str8[i]))
i++;
/*
Error, invalid day field
*/
if (str8[i])
{
if (on_error_exit)
my_error (121, filename, line, line_buffer, *d);
*y = -1;
}
}
}
else
/*
Error, invalid day field
*/
if ( (i > 1)
&& !isdigit(str8[1]))
{
if (on_error_exit)
my_error (121, filename, line, line_buffer, *d);
*y = -1;
}
/*
Check whether "n'th weekday of month" field exists
*/
if (*ptr_char)
if (!MY_ISSPACE(*ptr_char))
{
if (isdigit(*ptr_char))
{
*n = (*ptr_char - '0');
if (*n)
{
/*
Error, invalid "n'th weekday of month" field
*/
if ( (*n > 5)
&& (*n < 9))
{
if (on_error_exit)
my_error (117, filename, line, line_buffer, *n);
*y = -1;
}
}
}
else
/*
Error, missing separator between date part and `text'
*/
if (on_error_exit)
my_error (116, filename, line, line_buffer, 0);
if (*ptr_char)
ptr_char++;
/*
Error, missing separator between date part and `text'
*/
if (*ptr_char)
if ( !MY_ISSPACE(*ptr_char)
&& on_error_exit)
my_error (116, filename, line, line_buffer, 0);
/*
Error, "n'th weekday of month" entry set but invalid day encoded
*/
if ( *n
&& ( *d < DAY_MIN
|| *d > DAY_MAX))
{
if (on_error_exit)
my_error (121, filename, line, line_buffer, *d);
*y = -1;
}
(*len)++;
}
}
else
{
auto char *ptr2_char;
if (isdigit(*ptr_char))
ptr_char++;
/*
Error, missing separator between date part and `text'
*/
if (*ptr_char)
if ( !MY_ISSPACE(*ptr_char)
&& on_error_exit)
my_error (116, filename, line, line_buffer, 0);
/*
Compute standard date of '@' date variable date part of line
or '*' n'th weekday of year/weekday `ww[w]' of n'th week
in case an explicit year `yyyy' is given in date part
*/
i = atoi(str8);
ptr2_char = str8;
if ( *ptr2_char == *ASC_LIT
|| *ptr2_char == *DES_LIT)
ptr2_char++;
while (isdigit(*ptr2_char))
ptr2_char++;
if (*ptr2_char)
{
*hwd = compare_d_m_name (ptr2_char, DAy);
/*
Error, invalid textual short day name given
*/
if (!*hwd)
{
if (on_error_exit)
my_error (123, filename, line, line_buffer, 0);
*hc = '\0';
*d = 0;
*y = -1;
}
}
if (*y >= 0)
{
if (*hc == RC_EASTER_CHAR)
{
if (!precomp_date (i, *hwd, d, m, *y, EAster))
{
if (!*y)
{
/*
No explicit year `yyyy' given in date part of line
*/
*hn = i;
*d = 0;
*m = 0;
}
else
{
/*
Invalid relative date given
*/
*hc = '\0';
*d = 0;
*y = -1;
}
}
else
*hc = '\0';
}
else
if (islower(*hc))
{
/*
Try to assign local date variable if there is any set
else try to assign global date variable if there is any set,
otherwise we have to skip
*/
if ( rc_dvar[IDX(*hc)].l.month
|| rc_dvar[IDX(*hc)].g.month)
{
if (rc_dvar[IDX(*hc)].l.month)
{
*m = (int)rc_dvar[IDX(*hc)].l.month;
*d = (int)rc_dvar[IDX(*hc)].l.day;
}
else
{
*m = (int)rc_dvar[IDX(*hc)].g.month;
*d = (int)rc_dvar[IDX(*hc)].g.day;
}
if (!precomp_date (i, *hwd, d, m, *y, DVar))
{
if (!*y)
/*
No explicit year `yyyy' given in date part of line
*/
*hn = i;
else
{
/*
Invalid relative date given
*/
*hc = '\0';
*d = 0;
*y = -1;
}
}
else
*hc = '\0';
}
else
{
/*
Error, no such date variable defined
*/
if ( (warning_level >= 0)
&& on_error_exit)
dvar_warning (113, *hc, filename, line, line_buffer);
*hc = '\0';
*d = 0;
*y = -1;
}
}
else
if ( *hc == 'D'
|| *hc == 'W')
{
/*
Try to compute the '*' n'th weekday of year resp.,
weekday `ww[w]' of n'th week statement
*/
if (*y == 0)
{
/*
No explicit year `yyyy' given in date part of line
*/
*hn = i;
*d = 0;
*m = 0;
}
else
if (precomp_nth_wd (i, *hwd, hn, d, m, y,
((*hc == 'D') ? DAy : WEek)))
*hc = '\0';
}
else
/*
Error, either invalid date variable character trails holiday
mode character '@', or an invalid character trails the n'th
weekday of year resp., weekday `ww[w]' of n'th week mode character '*'
*/
if (on_error_exit)
my_error (123, filename, line, line_buffer, 0);
}
if (*ptr_char)
ptr_char++;
}
return(ptr_char);
}
# ifdef ANSI_PROTO
PUBLIC Bool
precomp_nth_wd ( int diff,
const int wd,
int *n,
int *day,
int *month,
int *year,
const Cmode_enum mode)
# else /* !ANSI_PROTO */
PUBLIC Bool
precomp_nth_wd (diff, wd, n, day, month, year, mode)
int diff;
const int wd;
int *n;
int *day;
int *month;
int *year;
const Cmode_enum mode;
# endif /* !ANSI_PROTO */
/*
Precompute the date of n'th absolute weekday `wd' in year or
the date on weekday `wd' of n'th absolute week in year and
return TRUE in case date exits in year, otherwise FALSE
*/
{
register int j=0;
auto int i=0;
if (*year)
{
if (mode == DAy)
{
*day = DAY_MIN;
*month = MONTH_MIN;
if (wd)
{
if ( diff == WEEK_MAX+1
|| diff == 99)
{
i = diff;
diff = WEEK_MAX;
}
}
else
{
/*
If special value 999 for `diff' is given,
set it to last day of year (365|366)
*/
if (diff == 999)
diff = DAY_LAST + (days_of_february (*year) == 29);
i = diff--;
}
}
else
{
/*
`mode' == WEek
*/
j = diff;
diff=i = weekno2jday (diff, *year);
if (diff > DAY_MIN)
diff--;
else
diff = 1;
if (jdate2sdate (diff, (days_of_february (*year)==29), day, month))
diff = 1;
}
}
if (!precomp_date (diff, wd, day, month, *year, DVar))
{
if (!*year)
{
/*
No explicit year `yyyy' given in date part of line
*/
*day = 0;
*month = 0;
*n = diff;
}
else
{
/*
Invalid relative date given
*/
*day = 0;
*month = 0;
*year = -1;
}
return(FALSE);
}
else
{
if ( wd
&& (mode == DAy))
{
register int year_old=*year;
if (i)
for (diff=DAY_MIN ; diff <= DAY_MAX ; diff++)
next_date (day, month, year);
if ( ( (*day <= DAY_MAX)
&& (*year != year_old))
|| weekday_of_date (DAY_MIN, MONTH_MIN, *year) == wd)
for (diff=DAY_MIN ; diff <= DAY_MAX ; diff++)
prev_date (day, month, year);
if (i == WEEK_MAX+1)
{
i = DAY_MIN;
*month = MONTH_MIN;
(void)precomp_date (WEEK_MAX, wd, &i, month, *year, DVar);
if ( (*day == i)
&& (weekday_of_date (DAY_MIN, MONTH_MIN, *year) != wd))
{
/*
Error, no such 53'rd weekday `ww[w]' of year
*/
*day = 0;
*month = 0;
*year = -1;
return(FALSE);
}
}
}
else
/*
`mode' == WEek
*/
if ( !wd
|| i < DAY_MIN
|| ( (j <= 1)
&& (*day == DAY_MAX+1)
&& (wd == DAY_MIN)))
{
if (*day >= DAY_MAX+i)
*day -= DAY_MAX;
else
if ( !wd
&& ( i < DAY_MIN
|| ( (*day == DAY_MIN+1)
&& (i == DAY_MIN))))
(*day)--;
if (*day < DAY_MIN)
{
/*
Error, n'th week doesn't contain such a weekday `ww[w]'
*/
*day = 0;
*month = 0;
*year = -1;
return(FALSE);
}
}
}
return(TRUE);
}
# ifdef ANSI_PROTO
PUBLIC Bool
precomp_date ( int diff,
const int wd,
int *day,
int *month,
const int year,
const Cmode_enum mode)
# else /* !ANSI_PROTO */
PUBLIC Bool
precomp_date (diff, wd, day, month, year, mode)
int diff;
const int wd;
int *day;
int *month;
const int year;
const Cmode_enum mode
# endif /* !ANSI_PROTO */
/*
Precompute the date relative to Easter Sunday's date(mode==EAster) or
relative to date variables date(mode==DVar) plus displacement `diff'
or displacement `diff' `wd' and return TRUE in case date exits in year,
otherwise FALSE
*/
{
register int i;
if ( ( (mode == EAster)
&& (year >= EASTER_MIN)
&& (year <= EASTER_MAX))
|| ( (mode == DVar)
&& (year >= YEAR_MIN)
&& (year <= YEAR_MAX)))
{
if (mode == EAster)
i = knuth_easter_formula (year);
else
i = day_of_year (*day, *month, year);
if (wd)
{
/*
Calculate date like: 3'rd(`diff') Friday(`wd') before Easter Sunday's date
*/
if ( wd < DAY_MIN
|| wd > DAY_MAX)
/*
Error, invalid weekday specified
*/
return(FALSE);
else
if (!diff)
/*
Error, a weekday but no difference specified
*/
return(FALSE);
else
{
register int act_wd;
auto int d;
auto int m;
auto int y=year;
jdate2sdate (i, (days_of_february (y)==29), &d, &m);
act_wd = weekday_of_date (d, m, y);
if (act_wd != wd)
{
if (diff < 0)
{
/*
Try to detect first weekday `wd' before actual date
*/
while (act_wd != wd)
{
prev_date (&d, &m, &y);
act_wd = weekday_of_date (d, m, y);
i--;
}
diff++;
}
else
{
/*
Try to detect first weekday `wd' after actual date
*/
while (act_wd != wd)
{
next_date (&d, &m, &y);
act_wd = weekday_of_date (d, m, y);
i++;
}
diff--;
}
}
if (y != year)
/*
Error, we have left year bounds
*/
return(FALSE);
/*
Calculate the difference
*/
i += (diff * DAY_MAX);
}
}
else
/*
Calculate the difference
*/
i += diff;
if (jdate2sdate (i, (days_of_february (year)==29), day, month))
return(TRUE);
}
return(FALSE);
}
# ifdef ANSI_PROTO
EXPORT Bool
set_dvar (const char *line_buffer,
const char *filename,
const int line,
const Dvar_enum mode)
# else /* !ANSI_PROTO */
EXPORT Bool
set_dvar (line_buffer, filename, line, mode)
const char *line_buffer;
const char *filename;
const int line;
const Dvar_enum mode;
# endif /* !ANSI_PROTO */
/*
Scans given string `line_buffer' and tries to detect valid date variable
references, which can be:
1) `dvar'=`mmdd' --> assignment of a constant date expression `mmdd'
2) `dvar'=`mmww[w]'<n> --> assignment of a dynamic date expression
n'th weekday `ww[w]' in month `mm'
3) `dvar'=*d<n>[`ww[w]'] --> assignment of a dynamic date expression
n'th weekday `ww[w]' of year
4) `dvar'=*w<n>[`ww[w]'] --> assignment of a dynamic date expression
weekday `ww[w]' of n'th week of year
5) `dvar'=`dvar' --> assignment of a date variable `dvar',
which must be already defined
6) `dvar'++ --> simple incrementation
7) `dvar'-- --> simple decrementation
8) `dvar'+=<n> --> addition of a constant numeric factor <n>
9) `dvar'-=<n> --> subtraction of a constant numeric factor <n>
a date variable name is valid from a...d and f...z (total 25 variables)
because the `e' variable is always reserved for current Easter
Sunday's date so we must skip any reference to this variable.
no whitespace characters may occur between date variable, operator
and value. Stores assignment (1)...(5) at position `date variable'
into global date variable vector `rc_dvar[]' (either the local or the
global ones, depending on given `mode', which can be either "GLobal"
or "LOcal". assignments (2)...(4) may be used ONLY in local date variables).
returns FALSE if an error occurs, otherwise TRUE.
*/
{
auto int i;
auto int n;
auto int m;
auto int d;
auto char op;
auto char op2;
auto const char *ptr_char=line_buffer;
auto Bool is_error=FALSE;
auto Bool skip_dvar_assign=FALSE;
/*
Skip and return error if invalid date variable name is given
*/
if ( ( isupper(*line_buffer)
|| islower(*line_buffer))
&& (tolower(*line_buffer) != RC_EASTER_CHAR))
{
ptr_char++;
/*
Check if assignment (1)...(5) is given
*/
if (*ptr_char != *RC_DVAR_ASSIGN)
{
if ( (*ptr_char != *RC_DVAR_ADD)
&& (*ptr_char != *RC_DVAR_SUB))
/*
Error, invalid first operator character found (no '+' or '-' given)
*/
is_error = TRUE;
else
{
/*
Check if operation (6)...(9) is given
*/
op = *ptr_char++;
if (*ptr_char)
{
op2 = *ptr_char++;
if ( op2 == op
|| op2 == *RC_DVAR_ASSIGN)
{
if (mode == GLobal)
{
m = (int)rc_dvar[IDX(*line_buffer)].g.month;
d = (int)rc_dvar[IDX(*line_buffer)].g.day;
}
else
{
m = (int)rc_dvar[IDX(*line_buffer)].l.month;
d = (int)rc_dvar[IDX(*line_buffer)].l.day;
}
if (m)
{
if ( ( (op2 == *RC_DVAR_ADD)
&& (m == MONTH_MAX)
&& (d == dvec[MONTH_MAX-1]))
|| ( (op2 == *RC_DVAR_SUB)
&& (m == MONTH_MIN)
&& (d == DAY_MIN)))
{
/*
Ignore line because year bounds are left
*/
skip_dvar_assign = TRUE;
if (warning_level >= 0)
dvar_warning (112, *line_buffer, filename, line, line_buffer);
}
else
{
/*
Compute day number of date in year
*/
i = mvec[m-1] + d;
if (m > 2)
i += is_leap_year;
/*
Either ++ or -- found
*/
if (op == op2)
{
if (op == *RC_DVAR_ADD)
/*
Increment date of date variable by 1
*/
i++;
else
/*
Decrement date of date variable by 1
*/
i--;
}
else
{
auto char str4[4];
/*
Either '+=' or '-=' found,
scan factor part (3 digits maximum, 0...365|366
*/
d = 0;
while ( isdigit(*ptr_char)
&& (d < 3))
str4[d++] = *ptr_char++;
str4[d] = '\0';
d = atoi(str4);
if (d > DAY_LAST+is_leap_year)
{
/*
Ignore line because an invalid displacement
factor is defined which lefts year bounds
*/
skip_dvar_assign = TRUE;
if (warning_level >= 0)
dvar_warning (112, *line_buffer, filename, line, line_buffer);
}
else
{
if (op == *RC_DVAR_ADD)
/*
Add factor to day number
*/
i += d;
else
/*
Subtract day number by factor
*/
i -= d;
}
}
/*
Calculate date in year
*/
if (!skip_dvar_assign)
{
if ( i < DAY_MIN
|| i > DAY_LAST+is_leap_year)
{
/*
Ignore line because year bounds are left
*/
skip_dvar_assign = TRUE;
if (warning_level >= 0)
dvar_warning (112, *line_buffer, filename, line, line_buffer);
}
else
/*
Calculate month and day
*/
(void)jdate2sdate (i, is_leap_year, &d, &m);
}
}
}
else
{
/*
Error, date variable undefined
*/
skip_dvar_assign = TRUE;
if (warning_level >= 0)
dvar_warning (113, *line_buffer, filename, line, line_buffer);
}
}
else
/*
Error, invalid second operator character found
(no '=', '+' or '-' given resp., illegal combination of '+' and '-')
*/
is_error = TRUE;
}
else
/*
Error, incomplete operator found (no +=, -=, ++ or -- given)
*/
is_error = TRUE;
}
}
else
{
/*
Assignment (1)...(5) to date variable found (simple '=' given),
scan expression part of date variable definition. assignments
(2)...(4) are ONLY allowed for local date variables.
*/
i = 0;
ptr_char++;
if (!*ptr_char)
/*
Error, no argument after '=' character given
*/
is_error = TRUE;
else
{
if ( ( isupper(*ptr_char)
|| islower(*ptr_char))
&& !isupper(*(ptr_char+1))
&& !islower(*(ptr_char+1)))
{
op = *ptr_char;
ptr_char++;
if ( !*ptr_char
|| MY_ISSPACE(*ptr_char))
{
if (tolower(op) == RC_EASTER_CHAR)
{
/*
Error, date variable invalid
*/
skip_dvar_assign = TRUE;
if (warning_level >= 0)
dvar_warning (112, *line_buffer, filename, line, line_buffer);
}
else
{
/*
If character after '=' is alphabetic and is not trailed
by digits, assume that assignment (5) given
*/
if (mode == GLobal)
{
m = (int)rc_dvar[IDX(op)].g.month;
d = (int)rc_dvar[IDX(op)].g.day;
}
else
{
m = (int)rc_dvar[IDX(op)].l.month;
d = (int)rc_dvar[IDX(op)].l.day;
}
}
}
else
/*
Error, invalid date variable name given
*/
is_error = TRUE;
}
else
{
auto int y=year;
auto int len;
auto Bool is_weekday_mode;
sprintf(str, "%0*d%s", len_year_max, y, ptr_char);
/*
rc_get_date() arguments `len' and `i' are dummys
only and must be given. they are not respected!
*/
(void)rc_get_date (str, &is_weekday_mode, &d, &m, &y, &n, &len,
&op, &i, &i, filename, line, line_buffer, TRUE);
if (y != -1)
{
/*
Check if assignments (3)...(4) are given
*/
if ( (mode == GLobal)
&& ( op
|| is_weekday_mode))
is_error = TRUE;
else
{
/*
Assignments (1)..(2) are given
*/
if ( m < MONTH_MIN
|| m > MONTH_MAX)
/*
Error, invalid month given
*/
is_error = TRUE;
else
{
i = dvec[m-1];
if (m == 2)
i += is_leap_year;
/*
Check for assignment (2) `dvar'=`mmww[w]'<n> (`ww'=mo...su,
`www'=mon..sun, n=1...5|9), e.g.:
x=03mo3 sets `x' to date of 3'rd Monday in March
x=03mon3 sets `x' to date of 3'rd Monday in March, too
*/
if (is_weekday_mode)
{
if (n == 9)
d = eval_holiday (i, m, year, d, FALSE);
else
{
d = eval_holiday (DAY_MIN, m, year, d, TRUE);
d += (DAY_MAX * (n - 1));
if (d > i)
{
/*
Month contains no such "n'th weekday of month"
ignore the assignment but produce NO error!!
*/
skip_dvar_assign = TRUE;
if (warning_level >= 0)
dvar_warning (112, *line_buffer, filename, line, line_buffer);
}
}
}
else
{
/*
Assume assignment (1) is given
*/
if (d == 99)
d = i;
if ( d < DAY_MIN
|| d > i)
/*
Error, invalid day given
*/
is_error = TRUE;
}
}
}
}
else
{
/*
Year contains no such date,
ignore the assignment but produce NO error!!
*/
skip_dvar_assign = TRUE;
if (warning_level >= 0)
dvar_warning (112, *line_buffer, filename, line, line_buffer);
}
}
}
}
if ( !is_error
&& !skip_dvar_assign)
{
/*
Store the assigned/calculated date
*/
if (mode == GLobal)
{
rc_dvar[IDX(*line_buffer)].g.month = (char)m;
rc_dvar[IDX(*line_buffer)].g.day = (char)d;
}
else
{
rc_dvar[IDX(*line_buffer)].l.month = (char)m;
rc_dvar[IDX(*line_buffer)].l.day = (char)d;
}
}
}
else
/*
Error, invalid date variable name given (not a...df...z)
*/
is_error = TRUE;
return((Bool)!is_error);
}
# ifdef ANSI_PROTO
PUBLIC void
nth_weekday_of_month ( int *d,
int *m,
int *y,
const int *n,
Bool *is_weekday_mode)
# else /* !ANSI_PROTO */
PUBLIC void
nth_weekday_of_month (d, m, y, n, is_weekday_mode)
int *d;
int *m;
int *y;
const int *n;
Bool *is_weekday_mode;
# endif /* !ANSI_PROTO */
/*
If "n'th weekday of month" field is encoded:
compute the according date and return it in &d, &m, &y;
if conversion error occurs, return &y==-1 (special value)
*/
{
register int i;
register int j=0;
auto int dd=0;
auto int mm=0;
auto Bool year_set=FALSE;
auto Bool year_modified=FALSE;
if ( *n
&& ( !rc_year_flag
|| ( *m
&& rc_year_flag))
&& ( !rc_period_list
|| ( *m
&& rc_period_list)))
{
if ( !*m
&& ( is_3month_mode
|| is_3month_mode2
|| fiscal_month > MONTH_MIN))
; /* If fiscal year resp., 3 month mode and no month encoded, skip evaluation */
else
{
*is_weekday_mode = FALSE;
if (!*y)
{
year_set = TRUE;
*y = year;
}
if (!*m)
{
*m = month;
/*
[-c][<n>]w or [-c]t option set:
lookahead whether week ends in month it started
*/
if ( rc_week_flag
|| rc_tomorrow_flag)
{
/*
<0000|`yyyy'>00`ww[w]'<n> event is in last week of last month of previous year
*/
if ( (*n > 3)
&& (day < DAY_MIN))
{
i = (days_of_february (year-1) == 29);
j = day + DAY_LAST + i;
(void)jdate2sdate (j, i, &dd, &mm);
}
else
if (*n == 1)
{
/*
<0000|`yyyy'>00`ww[w]'<n> event is in first week of next month of actual year
*/
if ( (day+DAY_MAX-1 > 0)
&& (day+DAY_MAX-1 < DAY_LAST+is_leap_year+1))
(void)jdate2sdate (day+DAY_MAX-1, is_leap_year, &dd, &mm);
else
{
/*
<0000|`yyyy'>00`ww[w]'<n> event is in first week first month of next year
*/
i = (days_of_february (year+1) == 29);
j = (day + DAY_MAX - 1) - (DAY_LAST + is_leap_year);
(void)jdate2sdate (j, i, &dd, &mm);
}
}
dd = *d;
}
}
else
if ( year_set
&& ( rc_week_flag
|| rc_tomorrow_flag))
{
if ( (*n == 9)
&& (*m == MONTH_MAX)
&& (*y > YEAR_MIN)
&& (day < DAY_MIN))
{
year_modified = TRUE;
(*y)--;
}
else
if ( (*n == 1)
&& (*m == MONTH_MIN)
&& (*y < YEAR_MAX)
&& (day+DAY_MAX >= DAY_LAST+is_leap_year))
{
year_modified = TRUE;
(*y)++;
}
}
if ( year_set
&& (*y < YEAR_MAX)
&& ( (fiscal_month > MONTH_MIN)
&& (*m < fiscal_month)))
if (!year_modified)
(*y)++;
if (*m == 2)
i = days_of_february (*y);
else
i = dvec[*m-1];
if (*n == 9)
*d = eval_holiday (i, *m, *y, *d, FALSE);
else
{
*d = eval_holiday (DAY_MIN, *m, *y, *d, TRUE);
*d += (DAY_MAX * (*n - 1));
/*
The "n'th weekday of month" doesn't occur in month:
skip it
*/
if (*d > i)
*y = -1;
}
/*
[-c][<n>]w or [-c]t option set:
correction for lookahead
*/
if ( mm
&& ( rc_week_flag
|| rc_tomorrow_flag))
{
if ( (*n == 1)
&& (mm != *m))
{
*m = mm;
if ( (day+DAY_MAX-1 > 0)
&& (day+DAY_MAX-1 < DAY_LAST+is_leap_year+1))
; /* Void, don't change year of event */
else
if ( year_set
&& (year < YEAR_MAX))
*y = year + 1;
*d = eval_holiday (DAY_MIN, *m, *y, dd, TRUE);
}
else
if ( (*n > 3)
&& ( ( adate_set
&& (mm == *m))
|| ( !adate_set
&& (mm != *m))))
{
if (!adate_set)
*m = mm;
if ( year_set
&& (year > YEAR_MIN))
*y = year - 1;
if (*n == 9)
*d = eval_holiday (dvec[MONTH_MAX-1], *m, *y, dd, FALSE);
else
{
*d = eval_holiday (DAY_MIN, *m, *y, dd, TRUE);
*d += (DAY_MAX * (*n - 1));
/*
The "n'th weekday of month" doesn't occur in month:
skip it
*/
if (*d > dvec[MONTH_MAX-1])
*y = -1;
}
}
}
}
}
}
# ifdef ANSI_PROTO
PUBLIC void
prev_date (int *day,
int *month,
int *year)
# else /* !ANSI_PROTO */
PUBLIC void
prev_date (day, month, year)
int *day;
int *month;
int *year;
# endif /* !ANSI_PROTO */
/*
Sets delivered date back by one day (to yesterdays date)
*/
{
(*day)--;
if ( !*day
|| !valid_date (*day, *month, *year))
{
(*month)--;
if (*month < MONTH_MIN)
{
*month = MONTH_MAX;
(*year)--;
}
if (*month == 2)
*day = days_of_february (*year);
else
*day = dvec[*month-1];
}
}
# ifdef ANSI_PROTO
PUBLIC void
next_date (int *day,
int *month,
int *year)
# else /* !ANSI_PROTO */
PUBLIC void
next_date (day, month, year)
int *day;
int *month;
int *year;
# endif /* !ANSI_PROTO */
/*
Sets delivered date forwards by one day (to tomorrows date)
*/
{
(*day)++;
if (!valid_date (*day, *month, *year))
{
*day = DAY_MIN;
if (*month == MONTH_MAX)
{
*month = MONTH_MIN;
(*year)++;
}
else
(*month)++;
}
}
# ifdef ANSI_PROTO
PUBLIC void
num2date (Ulint julian_days,
int *day,
int *month,
int *year)
# else /* !ANSI_PROTO */
PUBLIC void
num2date (julian_days, day, month, year)
Ulint julian_days;
int *day;
int *month;
int *year;
# endif /* !ANSI_PROTO */
/*
Converts a delivered absolute number of days `julian_days' to a standard date
(since 00010101(==`yyyymmdd'), returned in &day, &month and &year)
respecting the missing period of the Gregorian reformation
*/
{
auto double x;
auto Ulint jdays=date2num (GREG_F_DAY-1, GREG_MONTH, GREG_YEAR);
register int i;
if (julian_days > jdays)
julian_days += (Ulint)(GREG_L_DAY - GREG_F_DAY + 1);
x = (double)julian_days / (DAY_LAST + 0.25);
i = (int)x;
if ((double)i != x)
*year = i + 1;
else
{
*year = i;
i--;
}
if (julian_days > jdays)
{
/*
Correction for Gregorian years
*/
julian_days -= (Ulint)((*year / 400) - (GREG_YEAR / 400));
julian_days += (Ulint)((*year / 100) - (GREG_YEAR / 100));
x = (double)julian_days / (DAY_LAST + 0.25);
i = (int)x;
if ((double)i != x)
*year = i + 1;
else
{
*year = i;
i--;
}
if ( (*year % 400)
&& !(*year % 100))
julian_days--;
}
i = (int)(julian_days - (Ulint)(i * (DAY_LAST + 0.25)));
/*
Correction for Gregorian centuries
*/
if ( (*year > GREG_YEAR)
&& (*year % 400)
&& !(*year % 100)
&& (i < ((*year/100)-(GREG_YEAR/100))-((*year/400)-(GREG_YEAR/400))))
i++;
(void)jdate2sdate (i, (days_of_february (*year)==29), day, month);
}
# ifdef ANSI_PROTO
PUBLIC Slint
d_between (const int d1,
const int m1,
const int y1,
const int d2,
const int m2,
const int y2)
# else /* !ANSI_PROTO */
PUBLIC Slint
d_between (d1, m1, y1, d2, m2, y2)
const int d1;
const int m1;
const int y1;
const int d2;
const int m2;
const int y2;
# endif /* !ANSI_PROTO */
/*
Computes the amount of days between date1(base date) and date2
exclusive date1 and date2, and adds 1 to result
*/
{
return(date2num (d2, m2, y2)-date2num (d1, m1, y1));
}
# ifdef ANSI_PROTO
PUBLIC Slint
w_between (const int d1,
const int m1,
const int y1,
const int d2,
const int m2,
const int y2)
# else /* !ANSI_PROTO */
PUBLIC Slint
w_between (d1, m1, y1, d2, m2, y2)
const int d1;
const int m1;
const int y1;
const int d2;
const int m2;
const int y2;
# endif /* !ANSI_PROTO */
/*
Computes the amount of weeks between date1(base date) and date2
exclusive date1 and date2, and adds 1 to result
*/
{
auto Ulint date1=date2num (d1, m1, y1);
auto Ulint date2=date2num (d2, m2, y2);
auto Slint diff;
auto Slint result;
diff = (Slint)date2 - (date1 - (SYEAR(weekday_of_date (d1, m1, y1), start_day)) + 1);
result = diff / DAY_MAX;
if ( (diff % DAY_MAX)
&& (diff < 0L))
result--;
return(result);
}
# ifdef ANSI_PROTO
PUBLIC Slint
m_between (const int m1,
const int y1,
const int m2,
const int y2)
# else /* !ANSI_PROTO */
PUBLIC Slint
m_between (m1, y1, m2, y2)
const int m1;
const int y1;
const int m2;
const int y2;
# endif /* !ANSI_PROTO */
/*
Computes the amount of months between date1(base date) and date2
exclusive date1 and date2, and adds 1 to result
*/
{
return(((y2 - y1) * MONTH_MAX) + (m2 - m1));
}
# ifdef ANSI_PROTO
LOCAL void
dvar_warning (const int exit_status,
const char dvar,
const char *filename,
const int line,
const char *text)
# else /* !ANSI_PROTO */
LOCAL void
dvar_warning (dvar, filename, line, text)
const char dvar;
const char *filename;
const int line;
const char *text;
# endif /* !ANSI_PROTO */
/*
Prints a warning message in case an operation on a date variable is invalid
and terminates program if `warning_level' is set to max
*/
{
*str = '\0';
print_text (stderr, str, INternal);
switch (exit_status)
{
case 113:
# if USE_GER
sprintf(str, "Datumvariable `%c' undefiniert in Datei `%s'.", dvar, filename);
# else /* !USE_GER */
sprintf(str, "Date variable `%c' undefined in file `%s'.", dvar, filename);
# endif /* !USE_GER */
break;
case 112:
# if USE_GER
sprintf(str, "Datumwert ung"UE"ltig (Variable `%c') in Datei `%s'.", dvar, filename);
# else /* !USE_GER */
sprintf(str, "Invalid date value (variable `%c') in file `%s'.", dvar, filename);
# endif /* !USE_GER */
break;
default:
/*
This case MUST be an internal error!
*/
abort();
}
print_text (stderr, str, INternal);
# if USE_GER
if (!line)
sprintf(str, "Argument `%s' in Kommandozeile ignoriert", text);
else
sprintf(str, "Zeile %d ignoriert: %s", line, text);
# else /* !USE_GER */
if (!line)
sprintf(str, "Argument `%s' of command line ignored", text);
else
sprintf(str, "Line %d ignored %s", line, text);
# endif /* !USE_GER */
print_text (stderr, str, INternal);
if (warning_level >= WARN_LVL_MAX)
{
# if USE_GER
strcpy(str, "Abbruch!");
# else /* !USE_GER */
strcpy(str, "Abort!");
# endif /* !USE_GER */
print_text (stderr, str, INternal);
exit(exit_status);
}
}
#endif /* USE_RC */